package com.cfks.lanscript;

import java.time.format.*;
import java.util.*;
import java.time.*;

public class LanScriptRunner {
  static ArrayList<Val> valList = new ArrayList<>();
  static ArrayList<Function> funList = new ArrayList<>();
  static boolean inFunction = false;
  static LClass functionType = null;
  static String functionName = "";
  static Param[] functionParams = null;
  static Call[] functionCalls = null;
  static String runContext = "android";
  static ArrayList<FromThisVal> fromThisVal = new ArrayList<>();

  public static void run(String str) {
    String[] str1 = str.split("\n");
    ArrayList<Param> params = new ArrayList<>();
    ArrayList<Call> calls = new ArrayList<>();
    for (int i = 0; i < str1.length; i++) {
      String code = str1[i].trim();
      if (code.startsWith("public val")) {
        String[] code1 = code.split(" ");
        valList.add(new Val(code1[2], code1[3], code1[4]));
      } else if (code.startsWith("public fun")) {
        // 函数开始
        inFunction = true;
        params.clear();
        calls.clear();
        String[] code1 = code.split(" ");
        functionType = new LClass(code1[2].replace("F", ""));
        functionName = code1[3];
        for (int k = 4; k < code1.length - 1; k++) {
          if (!code1[k].equals("void")) {
            params.add(new Param(new LClass(code1[k].split(":")[1]), code1[k].split(":")[0]));
          }
        }
        functionParams = params.toArray(new Param[params.size()]);
      } else if (code.equals("funend")) {
        // 函数结束
        inFunction = false;
        String[] code1 = code.split(" ");
        functionCalls = calls.toArray(new Call[calls.size()]);
        funList.add(new Function(functionType, functionName, functionParams, functionCalls));
      } else if (code.startsWith("F")) {
        // 调用函数
        String[] code1 = code.split(" ");
        ArrayList<ParamValue> params1 = new ArrayList<>();
        for (int k = 1; k < code1.length; k++) {
          if (code1[k].startsWith("val:")) {
            for (int j = 0; j < valList.size(); j++) {
              if (valList.get(j).name.equals(code1[k].replace("val:", ""))) {
                params1.add(new ParamValue(ParamValue.from_val, valList.get(j).value));
                fromThisVal.add(new FromThisVal("Occupied"));
              }
            }
          } else if (code1[k].startsWith("this:") && inFunction == true) {
            // 函数传入的变量
            params1.add(new ParamValue(ParamValue.from_this_val, ""));
            fromThisVal.add(new FromThisVal(code1[k].replace("this:", "")));
          } else {
            params1.add(new ParamValue(ParamValue.from_value, code1[k]));
            fromThisVal.add(new FromThisVal("Occupied"));
          }
        }
        Call call =
            new Call(
                new LFunction(code1[0].replace("F", "")),
                params1.toArray(new ParamValue[params1.size()]));
        if (inFunction == true) {
          calls.add(call);
        } else {
          // 直接调用
          call.call();
        }
      }
    }
  }

  private static class Val {
    String name = "";
    String type = "";
    String value = "";

    Val(String name, String type, String value) {
      this.name = name;
      this.type = type;
      this.value = value;
    }
  }

  private static class Call {
    LFunction path = null;
    ParamValue[] params = null;

    Call(LFunction path, ParamValue[] params) {
      this.path = path;
      this.params = params;
    }

    public Object call() {
      return this.path.call(this.params);
    }
  }

  private static class Param {
    LClass type = null;
    String name = "";

    Param(LClass type, String name) {
      this.name = name;
      this.type = type;
    }
  }

  private static class ParamValue {
    static int from_val = 0;
    static int from_value = 1;
    static int from_this_val = 2;
    int from = ParamValue.from_val;
    String value = "";

    ParamValue(int from, String value) {
      this.value = value;
      this.from = from;
    }
  }

  private static class FromThisVal {
    String paramName = "";

    FromThisVal(String paramName) {
      this.paramName = paramName;
    }
  }

  private static class Function {
    String name = "";
    LClass type = null;
    Param[] params = null;
    Call[] code = null;

    Function(LClass type, String name, Param[] params, Call[] code) {
      this.name = name;
      this.type = type;
      this.params = params;
      this.code = code;
    }

    public Object call() {
      for (int i = 0; i < this.code.length; i++) {
        return this.code[i].call();
      }
      return null;
    }

    public Object call(ParamValue[] params) {
      for (int i = 0; i < this.code.length; i++) {
        return this.code[i].call();
      }
      return null;
    }
  }

  private static class LClass {
    String path = "";

    LClass(String path) {
      this.path = path;
    }

    public Function getFunction(String name) {
      return null;
    }

    public static LClass getLClass(String value) {
      if (value.startsWith("\"") && value.endsWith("\"")) {
        return new LClass("lan.lang.String");
      } else if (value.matches("[0-9]+")) {
        return new LClass("lan.lang.Number");
      }
      return null;
    }
  }

  private static class LFunction {
    String path = "";

    LFunction(String path) {
      this.path = path;
    }

    public Object call(ParamValue[] params) {
      if (this.path.startsWith("this/")) {
        // 是本地函数
        for (int j = 0; j < funList.size(); j++) {
          if (funList.get(j).name.equals(this.path.replace("this/", ""))) {
            for (int i = 0; i < fromThisVal.size(); i++) {
              if (!fromThisVal.get(i).paramName.equals("Occupied")) {
                for (int a = 0; a < funList.get(j).code.length; a++) {
                  for (int b = 0; b < funList.get(j).code[a].params.length; b++) {
                    if (funList.get(j).code[a].params[b].from == ParamValue.from_this_val) {
                      funList.get(j).code[a].params[b].value = params[b].value;
                    }
                  }
                }
              }
            }
            return funList.get(j).call(params);
          }
        }
      } else if (this.path.startsWith("lan/")) {
        // 系统自带函数
        switch (this.path) {
          case "lan/System/log":
            log(params[0].value);
            break;
          case "lan/System/setRunContext":
            runContext = params[0].value;
            break;
          default:
            break;
        }
      } else {
        // 外部导入函数
        return null;
      }
      return null;
    }
  }

  public static void log(String message) {
    System.out.println(
        "LanScriptLog "
            + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
            + "输出: "
            + message);
  }
}
